﻿using System.Security.Claims;
using GamFi.API.Application.Exceptions;
using GamFi.API.Application.Interfaces;
using GamFi.API.Application.Models;
using GamFi.API.Application.Resources;
using GamFi.API.Domain.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using MongoDB.Driver;

namespace GamFi.API.Application.Hubs;

[Authorize]
public class ChatHub(IDbContext dbContext, IMongoDatabase database, IUserContext userContext, IStringLocalizer<ExceptionMessages> localizer) : Hub
{
    private static readonly List<string> UsersOnline = [];

    /// <inheritdoc />
    public override async Task OnConnectedAsync()
    {
        var userId = Context.GetHttpContext()?.User.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value;
        UsersOnline.Add(userId!);

        await Clients.All.SendAsync("OnConnection", new
        {
            _usersOnline = UsersOnline
        });
    }

    /// <inheritdoc />
    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        var userId = Context.GetHttpContext()?.User.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value;
        UsersOnline.Remove(userId!);
        await Clients.All
            .SendAsync(
                "OnDisconnected", new
                {
                    _usersOnline = UsersOnline
                });
    }

    /// <summary>
    /// Отправка сообщения
    /// </summary>
    /// <param name="message"></param>
    public async Task SendMessageAsync(string message)
    {
        if (string.IsNullOrWhiteSpace(message))
            throw new ChatException(localizer[nameof(ChatException.MessageIsEmpty)]);

        if (userContext.CurrentUserId == null)
            throw new UserException(localizer[nameof(UserException.PermissionDenied)]);

        var userInfo = await dbContext.UserInfos.Include(u => u.User)
            .FirstOrDefaultAsync(u => u.UserId == userContext.CurrentUserId);

        if (userInfo is null)
            throw new UserException(localizer[nameof(UserException.UserByIdNotFound)]);

        if (userInfo.User is null)
            throw new UserException(localizer[nameof(UserException.UserByIdNotFound)]);

        var messageForDb = new Message
        {
            TextMessage = message,
            CreatedBy = userInfo.Id.ToString(),
            CreatedDate = DateTime.UtcNow,
        };

        var messagesCollection = database.GetCollection<Message>("Messages");
        await messagesCollection.InsertOneAsync(messageForDb);

        await Clients
            .All
            .SendAsync("ReceiveMessage", new SendMessageDto()
            {
                Id = Guid.Parse(messageForDb.Id),
                Text = message,
                WhoSentId = userContext.CurrentUserId.Value,
                SenderName = userInfo.User.UserName ?? "Unknown",
                SenderImageId = userInfo.ImageId,
            });
    }
}